package com.ruoyi.system.service.impl;

import com.ruoyi.system.domain.SysHealthData;
import com.ruoyi.system.mapper.SysHealthDataMapper;
import com.ruoyi.system.service.IHealthDataStatisticsService;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 健康数据统计服务实现类
 *
 * @author ruoyi
 */
@Service
public class HealthDataStatisticsServiceImpl implements IHealthDataStatisticsService {

    private final SysHealthDataMapper sysHealthDataMapper;

    public HealthDataStatisticsServiceImpl(SysHealthDataMapper sysHealthDataMapper) {
        this.sysHealthDataMapper = sysHealthDataMapper;
    }

    // 辅助方法

    private int getTotalDataCount(Long userId, Long deviceId) {
        SysHealthData queryParam = new SysHealthData();
        if (userId != null) {
            queryParam.setUserId(userId);
        }
        if (deviceId != null) {
            queryParam.setDeviceId(deviceId);
        }
        return sysHealthDataMapper.selectSysHealthDataList(queryParam).size();
    }

    private Date getLastUpdateTime(Long userId) {
        return getLastUpdateTime(userId, null);
    }

    private Date getLastUpdateTime(Long userId, Long deviceId) {
        SysHealthData queryParam = new SysHealthData();
        if (userId != null) {
            queryParam.setUserId(userId);
        }
        if (deviceId != null) {
            queryParam.setDeviceId(deviceId);
        }

        List<SysHealthData> dataList = sysHealthDataMapper.selectSysHealthDataList(queryParam);
        if (dataList.isEmpty()) {
            return null;
        }

        Optional<SysHealthData> latest = dataList.stream()
                .max(Comparator.comparing(SysHealthData::getUpdateTime));

        return latest.map(SysHealthData::getUpdateTime).orElse(null);
    }

    private List<Map<String, Object>> groupDataByInterval(List<SysHealthData> dataList, String interval) {
        List<Map<String, Object>> result = new ArrayList<>();
        if (dataList.isEmpty()) {
            return result;
        }
        Map<String, List<SysHealthData>> groupedData = new LinkedHashMap<>();
        for (SysHealthData data : dataList) {
            String timeKey = getTimeKey(data.getUpdateTime().getTime(), interval);
            groupedData.computeIfAbsent(timeKey, k -> new ArrayList<>()).add(data);
        }
        for (Map.Entry<String, List<SysHealthData>> entry : groupedData.entrySet()) {
            Map<String, Object> groupResult = new HashMap<>();
            groupResult.put("time", entry.getKey());
            List<SysHealthData> groupData = entry.getValue();
            if (!groupData.isEmpty()) {
                SysHealthData latest = groupData.get(groupData.size() - 1);
                groupResult.put("value", latest.getHeartRate());
                groupResult.put("count", groupData.size());
                groupResult.put("timestamp", latest.getUpdateTime());
            }
            result.add(groupResult);
        }
        return result;
    }

    private String getTimeKey(Long timestamp, String interval) {
        Date date = new Date(timestamp * 1000);
        SimpleDateFormat sdf;
        switch (interval.toLowerCase()) {
            case "hour":
                sdf = new SimpleDateFormat("yyyy-MM-dd HH");
                break;
            case "week":
                Calendar cal = Calendar.getInstance();
                cal.setTime(date);
                int week = cal.get(Calendar.WEEK_OF_YEAR);
                int year = cal.get(Calendar.YEAR);
                return year + "-W" + week;
            case "month":
                sdf = new SimpleDateFormat("yyyy-MM");
                break;
            case "day":
            default:
                sdf = new SimpleDateFormat("yyyy-MM-dd");
                break;
        }
        return sdf.format(date);
    }

    private long getTodayStartTimestamp() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return calendar.getTimeInMillis() / 1000;
    }
}